<?php

namespace App\Cost;

abstract class AbstractCost implements CostInterface
{
    /**
     * @var int 开单多少分钟内收费的分钟数
     */
    public int $startMinutes = 0;

    /**
     * @var int 开单多少分钟内收费的价格
     */
    public int $startMinutesPrice = 0;

    /**
     * @var ExceedType 超时收费模式
     */
    public ExceedType $exceedType;

    /**
     * @var int 当超时类型为 Interval 时，超时后限免分钟数
     */
    public int $exceedFreeMinutes = 0;

    /**
     * @var int 当超时类型为 Interval 时，超时后阶段计价分钟数
     */
    public int $exceedStageMinutes = 0;

    /**
     * @var int 当超时类型为 Interval 时，超时后 在限免分钟数 到 阶段计价分钟数 之间，用于计价的分钟数
     */
    public int $exceedStagePriceMinutes = 0;

    /**
     * @var int 封顶费用
     */
    public int $maxPrice = 0;

    public function getPrice(string $startTime, string $endTime): Price
    {
        //分钟数
        $minutes = (int)((strtotime($endTime) - strtotime($startTime)) / 60);

        if ($minutes < 0)
            throw new \Exception('传入的时间错误');

        if ($minutes == 0)
            return new Price();;

        if ($minutes < $this->startMinutes)
            return (new Price($this->startMinutesPrice))->setMessage("开单".$this->startMinutes."分钟内，按".round($this->startMinutesPrice/100, 2)."收费");

        $price =  $this->getCost($startTime, $endTime);

        if ($price->basePrice + $price->timeOutPrice > $this->maxPrice && $this->maxPrice > 0) {

            if ($price->basePrice > $this->maxPrice) {

                $price->basePrice = $this->maxPrice;
                $price->timeOutPrice = 0;
            } else {

                $price->timeOutPrice = $this->maxPrice - $price->basePrice;
            }

            $price->setMessage($price->message.",费用封顶为".round($this->maxPrice / 100, 2).'元');
        }

        return $price;
    }

    protected function getExceedFee($exceedMinutes): int|null
    {
        if ($this->exceedType == ExceedType::Minutes) {

            return (int)($this->getPricePerMinutes() * $exceedMinutes);
        } else if ($this->exceedType == ExceedType::Interval) {

            //小于免费时长，返回0
            if ($exceedMinutes <= $this->exceedFreeMinutes)
                return 0;

            //小于阶段分钟数 按 阶段计费分钟数 计费
            if ($exceedMinutes <= $this->exceedStageMinutes)
                return (int)($this->getPricePerMinutes() * $this->exceedStagePriceMinutes);

            //超过阶段计费分钟数，按60分钟计费
            if ($exceedMinutes <= 60)
                return (int)($this->getPricePerMinutes() * 60);

            return (int)($this->getPricePerMinutes() * $exceedMinutes);
        }
    }

    protected function getExceedMessage()
    {
        switch ($this->exceedType)
        {
            case ExceedType::Minutes:
                return "超出部分按实际分钟数计费。";
            case ExceedType::Interval:
                return "超时".$this->exceedFreeMinutes."分钟免费，超过".$this->exceedFreeMinutes."分钟至".$this->exceedStageMinutes."分钟，按".$this->exceedStagePriceMinutes."分钟计费；超过".$this->exceedStagePriceMinutes.'分钟，按60分钟计费';
            default:
                return null;
        }
    }

    /**
     * 获取计费结果
     * @param $minutes
     * @return Price
     */
    abstract protected function getCost(string $startTime, string $endTime): Price;

    /**
     * 获取计费方式每分钟金额
     * @return int
     */
    abstract protected function getPricePerMinutes(): float;
}
